using eccodes_jll

function setup_defs()
    install = expanduser("~/Downloads/FLEXINVERT/code/flexpart/third_party/eccodes-install")
    artifact = joinpath(dirname(dirname(eccodes_jll.eccodes)), "share", "eccodes")
    overlay = joinpath(@__DIR__, "deps", "eccodes_overrides")
    defs = [overlay,
            joinpath(install, "share", "eccodes", "definitions"),
            joinpath(artifact, "definitions")]
    samples = [joinpath(install, "share", "eccodes", "samples"),
               joinpath(artifact, "samples")]
    ENV["ECCODES_DEFINITION_PATH"] = join(filter(isdir, defs), ":")
    ENV["ECCODES_SAMPLES_PATH"] = join(filter(isdir, samples), ":")
end

setup_defs()

const lib = eccodes_jll.eccodes

function get_string_values(handle, key)
    size_ref = Ref{Clong}(0)
    err = ccall((:codes_get_size, lib), Cint, (Ptr{Cvoid}, Cstring, Ref{Clong}), handle, key, size_ref)
    println(key, " size: ", size_ref[], " status=", err)
    if err != 0 || size_ref[] == 0
        return String[]
    end
    # allocate array of pointers to char buffers
    n = Int(size_ref[])
    buf = [Vector{UInt8}(undef, 64) for _ in 1:n]
    ptrs = Ptr{UInt8}[pointer(b) for b in buf]
    err = ccall((:codes_get_string_array, lib), Cint, (Ptr{Cvoid}, Cstring, Ptr{Ptr{UInt8}}, Ref{Clong}), handle, key, pointer(ptrs), size_ref)
    println("string array err", err)
    return [String(takewhile(!=(0x00), b)) for b in buf]
end

function takewhile(pred, vec::Vector{UInt8})
    idx = findfirst(x -> !pred(x), vec)
    return idx === nothing ? vec : vec[1:idx-1]
end

function read_arrays(path)
    file = ccall(:fopen, Ptr{Cvoid}, (Cstring, Cstring), path, "rb")
    file == C_NULL && error("Cannot open file")
    err_ref = Ref{Cint}(0)
    handle = ccall((:codes_bufr_handle_new_from_file, lib), Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Ref{Cint}), C_NULL, file, err_ref)
    handle == C_NULL && error("no handle")
    ccall((:codes_set_long, lib), Cint, (Ptr{Cvoid}, Cstring, Clong), handle, "unpack", 1)
    desc_size = Ref{Clong}(0)
    ccall((:codes_get_size, lib), Cint, (Ptr{Cvoid}, Cstring, Ref{Clong}), handle, "expandedDescriptors", desc_size)
    desc_buf = Vector{Clong}(undef, desc_size[])
    ccall((:codes_get_long_array, lib), Cint, (Ptr{Cvoid}, Cstring, Ptr{Clong}, Ref{Clong}), handle, "expandedDescriptors", desc_buf, desc_size)
    println("descriptors length", length(desc_buf), " first", desc_buf[1:20])
    val_size = Ref{Clong}(0)
    ccall((:codes_get_size, lib), Cint, (Ptr{Cvoid}, Cstring, Ref{Clong}), handle, "numericValues", val_size)
    num_buf = Vector{Float64}(undef, val_size[])
    ccall((:codes_get_double_array, lib), Cint, (Ptr{Cvoid}, Cstring, Ptr{Float64}, Ref{Clong}), handle, "numericValues", num_buf, val_size)
    println("numeric len", length(num_buf), " first", num_buf[1:20])
    str_vals = get_string_values(handle, "stringValues")
    println("string sample", str_vals[1:10])
    ccall((:codes_handle_delete, lib), Cint, (Ptr{Cvoid},), handle)
    ccall(:fclose, Cint, (Ptr{Cvoid},), file)
end

read_arrays(ARGS[1])
